import wxRequestService from './service/wxRequestService';
import commons from './commons/commons';
import signService from './service/signService';

export default class MiniGameSdk {
    constructor() {
        this.version = '1.0.3' // sdk版本
        this.isInit = false; // 是否初始化完成
        this.isDebug = 0; // 是否调试
        this.appid = '' // 小游戏appid
        this.gameId = 0 // 游戏id
        this.channel = 2001 // 渠道id
        this.gameChannelId = 0 // 游戏渠道配置id
        this.packageId = 0 // 包id
        this.userInfo = {} // 用户信息
        this.deviceInfo = {} // 设备信息
        this.launchInfo = {} // 冷启动数据
        this.onShowInfo = {} // 热启动数据
        this.serverAppkey = 'a9330f4d727f9751eaea490e9311dda2' // 签名key
        this.serverHost = 'https://mtg-sdk-server.xingyi-games.com' // 请求服务器地址
        this.logHost = 'https://mtg-sdk-server.xingyi-games.com' // 上报日志服务器
        this.saveDeviceName = '#__sdkXyxDeviceId__' // 存储设备唯一id
        this.deviceNum = '' // 自定义设备id
        this.deviceNumTime = 0 // 自定义设备id的创建时间
        this.firstupIsSend = 0 // 是否已经上报激活给后端
        this.roleLoginNum = 0 // 防止研发过渡调用登录上报，此处做下统计判断
        this.loginInfo = {} // 登录返回信息
    }

    // 是否初始化完成
    checkInit() {
        return this.isInit
    }

    // 是否登录完成
    checkLogin() {
        return this.userInfo.hasOwnProperty('userId')
    }

    // 打印调试信息
    printDebug(...args) {
        if (!this.isDebug == 1) {
            return
        }
        let now = commons.formatDate(new Date(), 'YmdHis.u')
        let params = Array.prototype.slice.call(args);
        console.log('[SDK DEBUG]['+now+']', JSON.stringify(params))
    }

    // callback
    cbRes(func, res) {
        this.printDebug('回调请求结果原样', res)
        func(res)
    }

    // callback true
    cbTrue(func, data = {}) {
        this.printDebug('回调成功结果', data)
        func({
            code: 0,
            msg: 'success',
            data: data
        })
    }

    // callback fail
    cbFail(func, errno, errmsg, data={}) {
        this.printDebug('回调失败结果', errno, errmsg)
        func({
            code: errno,
            msg: errmsg,
            data: data
        })
    }

    // 显示消息提示框
    showTips(title, cb) {
        wx.showToast({
            title: title || '提示',
            icon: 'none',
            cb
        })
    }

    // 显示模态对话框
    showModal(params, cb = null) {
        wx.showModal({
            title: params.title || '提示',
            content: params.content,
            showCancel: false,
            confirmColor: '#0f77ff',
            success: cb
        })
    }

    // 根据platform获得device_type
    getDeviceTypeByPlatform(platform) {
        let list =  {
            andorid: 1,
            ios: 2,
            windows: 3,
            mac: 4,
            devtools: 5
        }

        return list[platform] || 0;
    }

    // 获得设备唯一id
    // localstorage存储是基于域名存储的，有可能出现一条域名多个游戏的情况，如
    // http://sdk.game.com/1001 和 http://sdk.game.com/1002
    // 所以我们判断此游戏是否已经缓存了设备信息时，要基于 gameid 作为索引去获取
    getDeviceNum(cb) {
        const _this = this
        var saveid = _this.saveDeviceName + _this.gameId
        wx.getStorage({
            key: saveid,
            complete (res) {
                if (res.data) {
                    return _this.cbTrue(cb, res.data)
                } else {
                    return _this.cbTrue(cb)
                }
            }
        })
    }

    // 设置设备唯一id
    setDeviceNum(data, cb = null) {
        const _this = this
        var saveid = _this.saveDeviceName + _this.gameId
        wx.setStorage({
            key: saveid,
            data: data,
            success(res) {
                if (cb) {
                    return _this.cbTrue(cb)
                }
            }
        })
    }

    // 上报日志
    addLog(event_id, event_name, params) {
        const _this = this

        // 基础信息
        params.event_id = event_id
        params.event_name = event_name
        params.event_time = Math.floor(Date.now() / 1000)

        // 补充额外数据
        params = Object.assign(_this.getExtendParams(), params)

        // 对数据进行签名
        params.time = Math.floor(Date.now() / 1000)
        let sign_info = signService.createSign(params, this.serverAppkey)
        params.sign = sign_info.sign
        _this.printDebug('签名源串', sign_info.str)

        let url = this.logHost + '/api/xyx/log'

        _this.printDebug('上报日志', url, params)

        return wxRequestService.sendLog(url, params, function(res){})
    }

    // 设备信息
    initDeviceInfo() {
        const _this = this
        wx.getNetworkType({
            complete(res) {
                if (res.hasOwnProperty('networkType')) {
                    _this.deviceInfo.net_work = res.networkType // 获得网络类型
                }
            }
        })

        let info = wx.getSystemInfoSync()
        _this.deviceInfo.device_screen_w = info.screenWidth
        _this.deviceInfo.device_screen_h = info.screenHeight
        _this.deviceInfo.device_os = info.model
        _this.deviceInfo.device_factory = info.brand
        _this.deviceInfo.device_system = info.system
        _this.deviceInfo.platform = info.platform
        _this.deviceInfo.device_type = _this.getDeviceTypeByPlatform(info.platform)

        return true;
    }

    // 小游戏冷启动时的参数
    initLaunch() {
        let info = wx.getLaunchOptionsSync()
        this.launchInfo.scene = info.scene
        this.launchInfo.query = info.query
        this.launchInfo.referrerInfo = info.referrerInfo
        this.launchInfo.chatType = info.chatType

        if (info.query.hasOwnProperty('package_id')) {
            this.packageId = info.query.package_id
        }

        this.printDebug('接收到冷启动参数', info)

        return true
    }

    // 小游戏热启动时的参数
    initOnShow(info) {
        this.onShowInfo.scene = info.scene
        this.onShowInfo.query = info.query
        if (info.query.hasOwnProperty('package_id')) {
            this.packageId = info.query.package_id
        }

        this.printDebug('接收到热启动参数', info)

        return true
    }

    // 获得额外参数，用于请求时附带上
    getExtendParams() {
        const _this = this
        let params = {}

        // 基础信息
        params.user_id = _this.userInfo.userId
        params.channel_openid = _this.userInfo.channelOpenid
        params.game_id = _this.gameId
        params.channel = _this.channel
        params.game_channel_id = _this.gameChannelId
        params.package_id = _this.packageId
        params.sdk_version = _this.version

        // 设备信息
        params.device_num = _this.deviceNum
        params.device_num_time = _this.deviceNumTime
        for (const key of ['device_type', 'imei', 'oaid', 'android_id', 'idfa', 'idfv', 'device_factory', 'device_os', 'device_system', 'device_screen_w', 'device_screen_h', 'package_name', 'sign_md5', 'net_work']) {
            if (_this.deviceInfo.hasOwnProperty(key)) {
                params[key] = _this.deviceInfo[key]
            }
        }

        // 启动参数
        params.launch_info = JSON.stringify(this.launchInfo)
        params.onshow_info = JSON.stringify(this.onShowInfo)

        return params
    }

    send(api, params = {}, cb) {
        const _this = this

        // 补充额外数据
        params = Object.assign(_this.getExtendParams(), params)

        // 对数据进行签名
        params.time = Math.floor(Date.now() / 1000)
        let sign_info = signService.createSign(params, this.serverAppkey)
        params.sign = sign_info.sign
        _this.printDebug('签名源串', sign_info.str)

        let url = this.serverHost + api

        _this.printDebug('发起SDK请求', url, params)

        return wxRequestService.send(url, params, cb)
    }

    // 上报激活
    sendFirstup(data) {
        const _this = this
        _this.printDebug('上报激活')
        _this.send('/api/h5/user/firstup', {}, function(res){
            if (res.code === 0) {
                data.is_send = 1
                _this.setDeviceNum(data)
                _this.firstupIsSend = 1
            }
        })
    }

    firstup() {
        const _this = this

        // 读取数据存储，是否为首次启动，是则上报激活
        _this.getDeviceNum(function(res) {
            if (res.data.device_num) {
                _this.deviceNum = res.data.device_num
                _this.deviceNumTime = res.data.create_time
                _this.firstupIsSend = res.data.is_send
                if (_this.firstupIsSend != 1) {
                    _this.sendFirstup(res.data)
                }

                _this.printDebug('获得设备唯一码信息', res)
            } else {
                // 如果有用户openid，则拿openid作为唯一设备码
                if (_this.checkLogin()) {
                    var device_num = _this.userInfo.channelOpenid
                } else {
                    // 随机生成一个设备码
                    var device_num = commons.uniqid()
                }

                let data = {
                    device_num: device_num,
                    create_time: Math.floor(Date.now() / 1000),
                    is_send: 0
                }
                _this.setDeviceNum(data, function(res) {
                    _this.deviceNum = data.device_num
                    _this.deviceNumTime = data.create_time
                    _this.sendFirstup(data)

                    _this.printDebug('设置设备唯一码信息', res)
                })
            }
        })
    }

    // 初始化
    init(params = {}, cb) {
        const _this = this
        if (_this.checkInit()) {
            return _this.cbFail(cb, 9999, '无需重复初始化')
        }

        ['game_id', 'game_channel_id'].forEach(function(item){
            if (!params.hasOwnProperty(item)) {
                let msg = '缺少参数: '+item
                return _this.cbFail(cb, 9999, msg)
            }
        })

        _this.gameId = params.game_id
        _this.gameChannelId = params.game_channel_id
        _this.isDebug = params.debug || 0
        _this.appid = params.appid || (wx.getAccountInfoSync ? wx.getAccountInfoSync().miniProgram.appId : '')
        if (_this.appid.length === 0) {
            return _this.cbFail(cb, 9999, 'appid 为空')
        }

        if (params.hasOwnProperty('server_host')) {
            _this.serverHost = params.server_host
        }
        if (params.hasOwnProperty('log_host')) {
            _this.logHost = params.log_host
        }

        _this.initDeviceInfo()
        _this.initLaunch()

        _this.isInit = true;
        _this.addLog(1002, 'init', {})

        // 进行登录，使用登录回来的用户openid进行激活
        _this.initLogin(function(res){
            if (res.code > 0) {
                return _this.cbFail(cb, res.code, res.msg)
            }
            // 完成初始化后进行激活上报
            _this.firstup()
            _this.printDebug('初始化成功', params)
            return _this.cbTrue(cb, _this.launchInfo)
        })
    }

    // 初始化既登录
    initLogin(cb) {
        const _this = this

        wx.login({
            success(res) {
                _this.send('/api/h5/user/login', {
                    access_token: res.code
                }, res => {
                    if (res.code !== 0) {
                        _this.printDebug('登录失败', res)
                        return _this.cbFail(cb, res.code, res.msg)
                    }
                    _this.userId = res.data.user_id
                    _this.userInfo.userId = res.data.user_id
                    _this.userInfo.channelOpenid = res.data.channel_openid
                    _this.userInfo.token = res.data.token
                    _this.userInfo.isReg = res.data.is_reg

                    _this.loginInfo = res

                    _this.printDebug('登录成功', res)
                    return _this.cbTrue(cb, res)
                })
            },
            fail(e) {
                _this.printDebug('登录失败', e.errCode, e.errMsg)
                return _this.cbFail(cb, e.errCode, e.errMsg)
            }
        })
    }

    // 登录
    login(params = {}, cb) {
        const _this = this
        if (!_this.checkInit()) {
            return _this.cbFail(cb, 9999, '初始化未完成')
        }

        return _this.cbTrue(cb, _this.loginInfo)
    }

    // 支付
    pay(params = {}, cb) {
        const _this = this

        if (!_this.checkLogin()) {
            return _this.cbFail(cb, 9999, '请先完成登录')
        }

        for (const item of ['game_trade_no','amount','goods_id','goods_name','server_id','server_name','role_id','role_name','role_level']) {
            if (!params.hasOwnProperty(item)) {
                let msg = '缺少参数: '+item
                return _this.cbFail(cb, 9999, msg)
            }
        }

        _this.send('/api/h5/pay/create', params, res => {
            _this.printDebug('发起支付', res)
            if (res.code !== 0) {
                _this.cbFail(cb, res.code, res.msg)
                return
            }
            let data = res.data
            let sdk_info = data.sdk_info
            let balance_info = sdk_info.balance_info
            let ios_info = sdk_info.ios_info

            // ios支付
            if (_this.deviceInfo.platform == 'ios') {
                wx.openCustomerServiceConversation({
                    sessionFrom: data.trade_no,
                    showMessageCard: true,
                    sendMessageTitle: ios_info.title,
                    sendMessagePath: ios_info.path,
                    sendMessageImg: ios_info.logo_url,
                    function(){
                        _this.cbTrue(cb)
                    },
                    function(){
                        _this.cbFail(cb, 9999, '拉起客服支付失败')
                    }
                })
                return
            } else {
                if (JSON.stringify(balance_info) == "{}") {
                    _this.cbFail(cb, 9999, '查询余额失败')
                    return
                }
                // 余额足够,直接回调
                if (balance_info.is_enough === 1) {
                    let api = '/api/h5/pay/client_callback/' + _this.gameChannelId
                    _this.send(api, balance_info.order_info, res => {
                        _this.cbRes(cb, res)
                        return
                    })
                } else {
                    // 余额不足 进行充值后扣费
                    _this.requestMidasPayment(balance_info.midas_payment, balance_info.order_info, cb)
                }
                return
            }
        }, res => {
            _this.cbFail(cb, res.code, res.msg)
        })
    }

    // 发起购买米大师币，购买成功后直接回调给后端进行扣费
    requestMidasPayment(midas_payment = {}, order_info = {}, cb) {
        const _this = this
        midas_payment.success = (res) => {
            let api = '/api/h5/pay/client_callback/' + _this.gameChannelId
            _this.send(api, order_info, (res) => {
                _this.cbRes(cb, res)
            })
        }
        midas_payment.fail = (error) => {
            _this.cbFail(cb, 9999, error.errMsg)
        }

        wx.requestMidasPayment(midas_payment)
    }

    // 直接打开客服
    goKefu(params, cb) {
        const _this = this
        if (!_this.checkLogin()) {
            _this.cbFail(cb, 9999, '请先登录')
        }

        wx.openCustomerServiceConversation({
            success: function(){
                _this.cbTrue(cb)
            },
            fail: function(){
                _this.cbFail(cb, 9999, '打开客服失败')
            }
        })
    }

    // 微信安全内容审核-文本检测
    msgSecCheck(params, cb) {
        const _this = this
        if (!_this.checkLogin()) {
            _this.cbFail(cb, 9999, '请先登录')
        }

        let api = '/api/h5/msg/check'
        _this.send(api, params, (res) => {
            _this.cbRes(cb, res)
        })
    }

    // 角色注册
    roleReg(params, cb) {
        const _this = this
        if (!_this.checkLogin()) {
            _this.cbFail(cb, 9999, '请先登录')
        }

        let api = '/api/h5/role/reg'
        _this.send(api, params, (res) => {
            _this.cbRes(cb, res)
        })
    }

    // 角色登录
    roleLogin(params, cb) {
        const _this = this
        if (!_this.checkLogin()) {
            _this.cbFail(cb, 9999, '请先登录')
        }

        // 如果过渡频繁请求，则直接停掉
        if (_this.roleLoginNum > 1) {
            _this.cbFail(cb, 9999, '请求上报登录次数过多了')
            return
        }

        let api = '/api/h5/role/login'
        _this.send(api, params, (res) => {
            _this.cbRes(cb, res)
        })
    }

    // 角色其他行为事件上报
    roleEvent(params, cb) {
        const _this = this
        if (!_this.checkLogin()) {
            _this.cbFail(cb, 9999, '请先登录')
        }

        // 基础信息
        params.event_time = Math.floor(Date.now() / 1000)

        // 补充额外数据
        params = Object.assign(_this.getExtendParams(), params)

        // 对数据进行签名
        params.time = Math.floor(Date.now() / 1000)
        let sign_info = signService.createSign(params, this.serverAppkey)
        params.sign = sign_info.sign
        _this.printDebug('签名源串', sign_info.str)

        let url = this.logHost + '/api/game/roleevent'

        _this.printDebug('上报日志', url, params)

        return wxRequestService.sendLog(url, params, cb)
    }
}
